﻿using System.Threading;

namespace Nutilities.Threading
{
    public abstract class ThreadClass : IThreadClass
    {
        public delegate void ThreadEvent(ThreadClass thread);
        
        public event ThreadEvent Started;
        public event ThreadEvent Stopped;
        public event ThreadEvent Paused;
        public event ThreadEvent Resumed;

        public bool Running { get; private set; }
        public bool IsPaused { get; private set; }
        public Thread Thread { get; private set; }

        public string ThreadName { get; set; }

        protected ThreadClass()
        {
            Thread = new Thread(Run);
        }

        public virtual void Start()
        {
            if (Thread.IsAlive)
            {
                throw new ThreadStateException("The thread is already running");
            }

            Running = true;
            if (Thread.Name == null)
            {
                Thread.Name = ThreadName;
            }
            Thread.Start();
            OnStarted();
        }

        public virtual void Stop()
        {
            Running = false;
            OnStopped();
        }

        public virtual void Join()
        {
            Thread.Join();
        }

        public virtual void Pause()
        {
            IsPaused = true;
            OnPaused();
        }

        public virtual void Resume()
        {
            IsPaused = false;
            OnResumed();
        }

        protected virtual void HandlePausedState()
        {
            while (IsPaused)
            {
                Thread.Sleep(10);
                Thread.Yield();
            }
        }

        protected virtual void OnStarted()
        {
            if (Started != null) Started(this);
        }

        protected virtual void OnStopped()
        {
            if (Stopped != null) Stopped(this);
        }

        protected virtual void OnPaused()
        {
            if (Paused != null) Paused(this);
        }

        protected virtual void OnResumed()
        {
            if (Resumed != null) Resumed(this);
        }

        protected abstract void Run();
    }
}
